//=====================================================================
//
// Designer   : fg
//
// Description:
//  5th CICIEC Nuclei Attendence Work
//	RISC-V Extension supported CIM mvm
// ====================================================================
`include "e203_defines.v"

    ////////////////////////////////////////////////////////////
	// NICE FSM 
	////////////////////////////////////////////////////////////
module nice_datapath (
	///////// NICE Interface
	input                         clk             ,
	input                         rst_n	          ,
	
	input  [`E203_XLEN-1:0]       nice_req_rs1    ,
	input  [`E203_XLEN-1:0]       nice_req_rs2 	  ,
	output [`E203_XLEN-1:0]       nice_rsp_rdat        ,
	output                        nice_rsp_err    	  ,
	// Memory lsu_req	
	output                        nice_icb_cmd_valid   ,
	input                         nice_icb_cmd_ready   ,
	output [`E203_ADDR_SIZE-1:0]  nice_icb_cmd_addr    ,
	output                        nice_icb_cmd_read    ,
	output [`E203_XLEN-1:0]       nice_icb_cmd_wdata   ,
	output [1:0]                  nice_icb_cmd_size    ,
	// Memory lsu_rsp	
	input                         nice_icb_rsp_valid   ,
	output                        nice_icb_rsp_ready   ,
	input  [`E203_XLEN-1:0]       nice_icb_rsp_rdata   ,
	input                         nice_icb_rsp_err	,

	/////////////////from controller
	input                        Isidle	      ,
	input                        Ispush	  ,
	input                        Ismvm	      ,
	input                        Issave	  ,

	input 						 custom3_push,
	input 						 custom3_mvm,
	input                        custom3_save,
	////////////////to intereface
	output    [1151:0]            o_push_buf,
	output                        o_start,
	output    [15:0]              o_row_index,
	output    [15:0]              o_col_index,
	output    [10:0]              o_row_length,
	output    [10:0]              o_col_length,
   
	input    [31:0]               i_result_buf,
	input                         i_result_done,
	output                        o_push_done,
	output                        o_save_done,
	/////////////////to controller 
	output 						  push_done,
	output 						  mvm_done,
	output 						  save_done
	);

	localparam PUSH_MAX_SIZE = 36;
	localparam SAVE_MAX_SIZE = 64;
    assign nice_rsp_err = nice_icb_rsp_err & nice_icb_rsp_valid&nice_icb_rsp_ready;
    assign nice_rsp_rdat = 0;
   
	reg [6:0] push_cnt_r;
	wire nice_icb_cmd_hsked = nice_icb_cmd_valid&nice_icb_cmd_ready;
	wire Is2mem = Ispush | Issave;
	wire custom_mem = custom3_push | custom3_save;
	////////////// 1.mem req
	assign nice_icb_cmd_valid = custom3_push| custom3_save|Is2mem;
	assign nice_icb_cmd_read  = ~(Issave|(Isidle & custom3_save));  //?
	assign nice_icb_cmd_size  = 2'b10;

	wire maddr_acc_ena;
	assign maddr_acc_ena = (Isidle& custom_mem)|(nice_icb_cmd_hsked&Is2mem);
	reg [`E203_ADDR_SIZE-1:0] maddr_acc_r;

	assign nice_icb_cmd_addr  = (Isidle & custom_mem) ? nice_req_rs1 :maddr_acc_r;

	always @(posedge clk or negedge rst_n)begin 
		if(~rst_n) begin
			maddr_acc_r    <=#1 0;
		end
		else if(maddr_acc_ena)begin
			maddr_acc_r    <=#1  nice_icb_cmd_addr+ `E203_ADDR_SIZE'h4;
		end
	end
	
	reg [6:0] transize; //load time from e203 mem
	//reg [10:0]row_index_r;
	//reg [10:0]data_num_r;
	always @(posedge clk or negedge rst_n)begin 
		if(~rst_n) begin
			transize    <=#1 0;
			//row_index_r <=#1 0;
			//data_num_r  <=#1 0;
		end
		else if(Isidle & custom3_push) begin
			//transize 	  <=#1 rs2[10:4] + 7'b1;
			transize  	<=#1  7'd35;
			//row_index_r   <=#1 rs2[21:11];
			//data_num_r    <=#1 rs2[10:0];
		end
		else if(Isidle & custom3_save)begin
			//transize 	  <=#1 rs2[10:1] + 7'b1;
			transize 	  <=#1 7'd64;    //
			//row_index_r   <=#1 rs2[21:11];
			//data_num_r    <=#1 rs2[10:0];
		end
	end

	always @(posedge clk or negedge rst_n)begin 
		if(~rst_n) begin
			push_cnt_r    <=#1 0;
		end
		else if (push_done)begin
              push_cnt_r <= #1 0;
         end
		else if(nice_icb_cmd_hsked & Is2mem)begin
			push_cnt_r 	  <=#1 push_cnt_r + 3'b1;
		end
		else if(push_cnt_r == transize)begin
			push_cnt_r 	  <=#1 0;
		end
	end

	assign push_done   	= Ispush  &(push_cnt_r == transize);
//	assign save_done 	= Issave  &(push_cnt_r == transize);
	

	//////////////// 2.mem rsp
	assign nice_icb_rsp_ready = 1'b1;
	wire nice_icb_rsp_hsked =nice_icb_rsp_valid & nice_icb_rsp_ready ;

	wire push_rsp_hsked   =  nice_icb_rsp_hsked & Ispush;
//	assign lstate_rsp_hsked =  nice_icb_rsp_hsked & Issave;

	//////2.1 load push_buf
	reg  [`E203_XLEN-1:0] push_buf_r [PUSH_MAX_SIZE-1:0];
	wire [PUSH_MAX_SIZE-1:0] pushbuf_we;

	genvar i;
	for (i=0; i<PUSH_MAX_SIZE; i=i+1)
	begin:pushbufGen
		assign pushbuf_we[i] = push_rsp_hsked & ( push_cnt_r  == i );
		always @(posedge clk or negedge rst_n) begin 
			if(~rst_n) begin
				push_buf_r[i] <=#1 0;
			end else if(pushbuf_we[i]) begin
				push_buf_r[i] <=#1 nice_icb_rsp_rdata;
			end
		end
	end

	///////// 3.save state
	reg [6:0]save_cmd_cnt_r;

	wire save_cmd_cnt_inc = (Isidle & custom3_save) |(Issave &nice_icb_rsp_hsked);
	always @(posedge clk or negedge rst_n) begin 
		if(~rst_n) begin
			save_cmd_cnt_r <=#1 0;
		end	else if(save_cmd_cnt_inc ) begin
			save_cmd_cnt_r <=#1 save_cmd_cnt_r + 7'b1;
		end else 
			save_cmd_cnt_r <=#1 0;
	end
	wire  save_cnt_transize = (save_cmd_cnt_r == transize);
    assign save_done = Issave & save_cnt_transize;

    wire [`E203_XLEN-1:0] save_buf [SAVE_MAX_SIZE-1:0];
    assign nice_icb_cmd_wdata =(save_cmd_cnt_inc & (~save_cnt_transize))? save_buf[save_cmd_cnt_r]:0;
    /// 4. mvm
    reg mvm_start;
    always @(posedge clk or negedge rst_n) begin : mvm
    	if(~rst_n) begin
    		mvm_start <= 0;
    	end else if(Isidle & custom3_mvm)begin
    		mvm_start <= 1'b1;
    	end else
    		mvm_start <= 1'b0;
    end
    reg [15:0] row_index_r,col_index_r;
    reg [10:0] row_length_r,col_length_r;
    always @(posedge clk or negedge rst_n) begin : mvm_row
    	if(~rst_n) begin
    		row_index_r <= 0;
    		col_index_r <= 0;
    		row_length_r <= 0;
    		col_length_r <= 0;
    	end else if(Isidle & custom3_mvm)begin
    		row_index_r <= nice_req_rs1[31:16];
    		col_index_r <= nice_req_rs1[15:0];
    		row_length_r <= nice_req_rs2[21:11];
    		col_length_r <= nice_req_rs2[10:0];
    	end else if(Ismvm & mvm_done)begin
    		row_index_r <= 0;
    		col_index_r <= 0;
    		row_length_r <= 0;
    		col_length_r <= 0;
    	end
    end

 //   wire [1:0] push_buf_mvm[0:576-1];
    wire [`E203_XLEN*36-1:0]push_buf_wire ;
    wire [`E203_XLEN*64-1:0]save_buf_wire ;
    for (i=0; i<36; i=i+1)begin
            assign push_buf_wire[`E203_XLEN*(i+1)-1:`E203_XLEN*i] = push_buf_r[i];
    end
    for (i=0; i<64; i=i+1)begin
            assign save_buf[i] = save_buf_wire[`E203_XLEN*(i+1)-1:`E203_XLEN*i] ;
    end
    
//    cim_mvm u_mvm(
//    	.clk(clk),
//    	.rst_n(rst_n),
//    	.start(mvm_start),
//    	.row_index(row_index_r),
//    	.col_index(col_index_r),
//    	.row_length(row_length_r),
//    	.col_length(col_length_r),
//    	.push_buf(push_buf_wire),
//    	.save_buf(save_buf_wire),  //out
//    	.mvm_done(mvm_done)

//    );
assign o_row_index = row_index_r;
assign o_col_index = col_index_r;
assign o_row_length = row_length_r;
assign o_col_length = col_length_r;

assign o_push_done = push_done;
assign o_save_done = save_done;
assign o_start = mvm_start;
assign o_push_buf = push_buf_wire;  
assign mvm_done = i_result_done;
assign save_buf_wire = i_result_buf;
endmodule

module EndianCnvt #(parameter NUMLENGTH = 128)(
	//This module is used for endian convertion from little 2 big, or vice versa.
	input [NUMLENGTH-1:0]	NumIn,
	output [NUMLENGTH-1:0]	NumOut
	);

	localparam BYTENUM = NUMLENGTH/8;

	genvar i;
	for (i=0; i<BYTENUM; i=i+1)
	begin:EndianCnvtGen
		assign NumOut[(i+1)*8-1:i*8] = NumIn[(BYTENUM-i)*8-1:(BYTENUM-i-1)*8];
	end
endmodule

